﻿namespace Resonator.Core.Services
{
	using System;
	using System.Collections;
	using System.Collections.Generic;
	using System.Threading;
	using Castle.ActiveRecord;
	using NHibernate;
	using NHibernate.Expressions;
	using NHibernate.SqlCommand;
	using Queries;
	using Resonator.Domain.Models;
	using Resonator.Domain.Services;

	public class ResourceImporter : IResourceImporter
	{
		private readonly IRepository<Resource> _resourceRepository;

		public ResourceImporter(IRepository<Resource> resourceRepository)
		{
			if( resourceRepository == null )
			{
				throw new ArgumentNullException( "resourceRepository" );
			}

			_resourceRepository = resourceRepository;
		}

		public virtual void Import(IEnumerable<Resource> resources)
		{
			Dictionary<string, Resource> resourcesToImport = new Dictionary<string, Resource>();

			List<DetachedCriteria> searchCriteria = new List<DetachedCriteria>(); 

			foreach( Resource resource in resources )
			{
				resourcesToImport[resource.Phrase] = resource;
				searchCriteria.Add( Where.Resource.Phrase == resource.Phrase && Where.Resource.Translations.With( JoinType.LeftOuterJoin, FetchMode.Join ) ); 
			}

			if( searchCriteria.Count == 0 ) return;

			using( ISessionScope scope = _resourceRepository.CreateSessionScope() )
			{
				Resource[] dbResources = _resourceRepository.FindAll( searchCriteria.ToArray() );

				foreach( Resource dbResource in dbResources )
				{
					Resource resourceToImport;
					bool dbResourceUpdated = false;

					if( resourcesToImport.TryGetValue( dbResource.Phrase, out resourceToImport ) )
					{
						resourcesToImport.Remove( dbResource.Phrase );

						foreach( Translation translationToImport in resourceToImport.Translations )
						{
							bool dbTranslationExists = false;
							foreach( Translation dbTranslation in dbResource.Translations )
							{
								if( dbTranslation.Culture.Equals( translationToImport.Culture ) )
								{
									if( dbTranslation.Phrase != translationToImport.Phrase )
									{
										dbTranslation.Phrase = translationToImport.Phrase;
										dbResourceUpdated = true;
									}
									dbTranslationExists = true;
									break;
								}
							}

							if( !dbTranslationExists )
							{
								dbResource.AddTranslation( translationToImport );
								dbResourceUpdated = true;
							}
						}
					}
					else
					{
						throw new ResonatorException(string.Format("We queried for a Resource that we didn't need '{0}'", dbResource.Phrase));
					}

					// Remove unchanged Resources from NHibernate's change tracking
					if( !dbResourceUpdated )
					{
						scope.Evict( dbResource );
					}
				}

				foreach( Resource resourceToImport in resourcesToImport.Values )
				{
					_resourceRepository.Save( resourceToImport );
				}
			}
		}
	}
}